import  cv2
import numpy
import copy

#视频路径
videoFileName = r'./vtest.avi'
#1. 在测试视频(OpenCV安装目录\sources\samples\data)上，使用基于混合高斯模型的背景提取算法，提取前景并显示(显示二值化图像，前景为白色)。
'''
cap = cv2.VideoCapture(videoFileName)
#混合高斯建模
fgbg = cv2.createBackgroundSubtractorMOG2()
thresh = 200

while True:
    ret,frame = cap.read()
    if not ret:
        break

    fgmask = fgbg.apply(frame)
    _,fgmask = cv2.threshold(fgmask, 30, 0xff, cv2.THRESH_BINARY)

    bgImage = fgbg.getBackgroundImage()
    _,cnts,_ = cv2.findContours(fgmask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cv2.imshow('frame',frame)
    cv2.imshow('blackground_white',fgmask)

    #检测是否终止
    key = cv2.waitKey(30)
    if key == 27:
       break

cap.release()
cv2.destroyAllWindows()


#2. 在1基础上，将前景目标进行分割，进一步使用不同颜色矩形框标记，并在命令行窗口中输出每个矩形框的位置和大小。

#获取视频
cap = cv2.VideoCapture(videoFileName)
#混合高斯建模
fgbg = cv2.createBackgroundSubtractorMOG2()
thresh = 200

while True:
    ret,frame = cap.read()
    if not ret:
        break

    fgmask = fgbg.apply(frame)
    _,fgmask = cv2.threshold(fgmask, 30, 0xff, cv2.THRESH_BINARY)

    bgImage = fgbg.getBackgroundImage()
    _,cnts,_ = cv2.findContours(fgmask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    count = 0
    site = []
    size = []
    for c in cnts:
        area = cv2.contourArea(c)
        if(area < thresh):
            continue
        count += 1
        size.append(area)

        x, y, w, h = cv2.boundingRect(c)
        site.append([x,y, x+w, y+h])
        cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 0xff, 0), 2)
        cv2.putText(frame,str(count),(x,y),cv2.FONT_HERSHEY_PLAIN,2.0,(0,0xff,0))

    print('共检测到', count, '个目标', '；位置为', site, '；对应大小为 ', size,  '\n')
    cv2.imshow('frame',frame)
    cv2.imshow('blackground', bgImage)

    #检测是否终止
    key = cv2.waitKey(30)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()

'''
#3. 安装ImageWatch，并在代码中通过设置断点，观察处理中间结果图像。

#扩展作业：
#4. 使用光流估计方法，在前述测试视频上计算特征点，进一步进行特征点光流估计。
#角点检测参数

feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7,
                       blockSize = 7)
#L_k光流估计
lk_params = dict( winSize = (15,15),
                  maxLevel = 2,
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
cap = cv2.VideoCapture(videoFileName)

#计算第一帧特征点
ret, prev = cap.read()
prevGray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(prevGray, mask = None, **feature_params)

while True:
    ret, frame =cap.read()
    if not ret:
        break

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    #计算光流
    p1, st, err = cv2.calcOpticalFlowPyrLK(prevGray, gray, p0, None, **lk_params)

    #选取好的跟踪点
    goodPoints = p1[st == 1]
    goodPrevPoints = p0[st == 1]

    #在结果图像中画出特征点和计算出来的光流向量
    res = frame.copy()
    drawColor = (0, 0, 255)
    for i, (cur, prev) in enumerate(zip(goodPoints, goodPrevPoints)):
        x0, y0 = cur.ravel()
        x1, y1 = prev.ravel()
        cv2.line(res, (x0, y0), (x1, y1), drawColor)
        cv2.circle(res, (x0, y0), 4, drawColor)

    #更新上一帧
    prevGray = gray.copy()
    p0 = goodPoints.reshape(-1, 1, 2)

    #显示计算的图像
    cv2.imshow('检测结果',res)

    key = cv2.waitKey(30)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()






